/*
 * Copyright (c) 2016-2021, Hangzhou Qulian Technology Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#include "utils.h"

//cal how many bytes the value in need
ql_size_t GetHexNumericSize(ql_uint64_t in) {
    ql_size_t ret = 0;
    do{
        in >>= 8;
        ret++;
    }while(in);
    return ret;
}

//alloc mem and copy from str， the copy len is min{slen, strlen}
//if str == NULL, this function just alloc mem
ql_byte_t* StrMalloc(ql_byte_t* str, ql_size_t slen) {
    ql_byte_t *ret = (ql_byte_t*)calloc(slen + 1, sizeof(ql_byte_t));
    if(ret == NULL)return ret;
    if(str == NULL || slen == 0)return ret;
    memcpy(ret, str, slen);
    return ret;
}

//alloc mem for struct ql_strings_t and init it. return NULL if failed
ql_strings_t* CreateStringsT() {
    ql_strings_t* ret = (ql_strings_t*)calloc(1, sizeof(ql_strings_t));
    if(ret == NULL)return NULL;
    ret->val = NULL;
    ret->next = NULL;
    ret->len = 0;
    return ret;
}

//free the ql_strings_t list
void FreeStringsT(ql_strings_t* in) {
    ql_strings_t* now = in;
    while(now) {
        in = now->next;
        free(now->val);
        free(now);
        now = in;
    }
}

//convert a numeric value to bytes array. for example 0xaabbcc -> aa bb cc
ql_strings_t* NumericToHexbytes(ql_uint64_t in) {
    ql_int64_t size = GetHexNumericSize(in);
    ql_strings_t* ret;
    ql_size_t i = 0;

    if(size <= 0)return NULL;
    ret = CreateStringsT();
    if(ret == NULL)return NULL;//if alloc mem failed
    ret->len = size;
    ret->val = (ql_byte_t*)calloc(size, sizeof(ql_byte_t));
    if(ret->val == NULL) {//if alloc mem failed
        FreeStringsT(ret);
        return NULL;
    }
    for(i = 0; i < size; i++) {
        ret->val[size-1 - i] = in & 0xff;
        in >>= 8;
    }
    return ret;
}

char* BytesToHexstring(ql_byte_t* in, ql_int64_t inlen) {
    char hex[] = "0123456789abcdef";
    ql_size_t i = 0;
    char* ret;

    if(inlen < 0)return NULL;
    ret = (char*)calloc(inlen*2 + 1, sizeof(char));
    if(ret == NULL)return NULL;
    for(i = 0; i < inlen; i++) {
        ret[i<<1] = hex[ (in[i]>>4) & 0x0f ];//i*2
        ret[(i<<1)|1] = hex[ in[i] & 0x0f ];//i*2+1
    }
    ret[inlen*2] = 0;
    return ret;
}

ql_byte_t hexcharToByte(char chr) {
    if(chr >= '0' && chr <= '9')return chr - '0';
    if(chr >= 'a' && chr <= 'f')return chr - 'a' + 10;
    if(chr >= 'A' && chr <= 'F')return chr - 'A' + 10;
    return 0xff;//err
}

ql_strings_t* HexstringToBytes(char *in) {
    if(in == NULL)return NULL;
    ql_size_t inlen = strlen(in);
    char *ptr = in;
    ql_strings_t *ret;
    ql_size_t i = 0;

    if(inlen >= 2 && in[0] == '0' && in[1] == 'x'){
        ptr = in + 2;//ignore prefix "0x"
        inlen -= 2;
    }
    if(inlen & 1)return NULL;//odd len
    ret = CreateStringsT();
    if(ret == NULL)return NULL;
    ret->val = (ql_byte_t*)calloc((inlen >> 1) + 1, sizeof(ql_byte_t));
    if(ret->val == NULL) {
        FreeStringsT(ret);
        return NULL;
    }
    ret->len = inlen >> 1;
    for(i = 0; i < ret->len; i++) {
        ql_byte_t H = hexcharToByte(ptr[i<<1]);//i*2
        ql_byte_t L = hexcharToByte(ptr[(i<<1) | 1]);//i*2 + 1
        if(H == 0xff || L == 0xff) {
            FreeStringsT(ret);
            return NULL;
        }
        ret->val[i] = (H << 4) | L;
    }
    return ret;
}